package cn.basttg.demo.zookeeper;

import java.util.List;

import net.sf.json.JSONObject;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;

public class ZkMain implements Watcher {

	// 工具信息
	private final static String TOOL_NAME = "ZooKeeper工具 ";
	private final static String TOOL_VERSION = "V0.2";
	private final static String TOOL_AUTHOR = "陈格生";
	private final static String TOOL_COPYRIGHT = "©2012 KEDACOM 版权所有";

	// 相关命令编号
	private final static int ACTION_QUERY = 1;
	private final static int ACTION_CREATE = 2;
	private final static int ACTION_MODIFY = 3;
	private final static int ACTION_DELETE = 4;
	private final static int ACTION_DEMO = 5;
	private final static int ACTION_CONFIG = 8;
	private final static int ACTION_ABOUT = 9;
	private final static int ACTION_QUIT = 0;

	// 默认配置信息
	private final static String DEFAULT_HOST = "172.16.160.196";
	private final static int DEFAULT_PORT = 2181;
	private final static int DEFAULT_TIMEOUT = 30000;

	// 当前配置信息
	private static String zkHost = DEFAULT_HOST;
	private static int zkPort = DEFAULT_PORT;
	private static int zkTimeout = DEFAULT_TIMEOUT;

	private static ZooKeeper zooKeeper = null;
	private Integer mutex;

	ZkMain() {
		if (zooKeeper == null) {
			try {
				System.out.println("Starting ZkMain:");
				zooKeeper = new ZooKeeper(zkHost + ":" + zkPort, 3000, this);
				mutex = new Integer(-1);
				System.out.println("Finished starting ZkMain: " + zooKeeper);
			} catch (Exception e) {
				System.out.println(e.toString());
				zooKeeper = null;
			}
		}
		// else mutex = new Integer(-1);
	}
	
	synchronized public void process(WatchedEvent event) {
		synchronized (mutex) {
			mutex.notify();
		}
	}

	public static void main(String[] args) {
		ZkMain zkMain = new ZkMain();
		try {
			zkMain.openZk();

			StartMenu();
			while (true) {
				int operate = Integer.parseInt(getCommand());
				switch (operate) {
					case ACTION_QUERY:
						zkMain.queryData();
						break;
					case ACTION_CREATE:
						zkMain.createData();
						break;
					case ACTION_MODIFY:
						zkMain.modifyData();
						break;
					case ACTION_DELETE:
						zkMain.deleteData();
						break;
					case ACTION_DEMO:
						zkMain.runDemo();
						break;
					case ACTION_CONFIG:
						zkMain.configConnection();
						break;
					case ACTION_ABOUT:
						about();
						break;
					case ACTION_QUIT:
						exit();
						break;
					default:
						System.out.println("没有该命令 " + operate);
						break;
				}
			}
		} catch (Exception e) {
			System.out.println("输入错误，错误信息如下： ");
			e.printStackTrace();
		}
	}

	// 开始菜单
	public static void StartMenu() {
		System.out.println("**********" + TOOL_NAME + " " + TOOL_VERSION + "**********");
		System.out.println(ACTION_QUERY + "、查询目录信息");
		System.out.println(ACTION_CREATE + "、创建目录节点");
		System.out.println(ACTION_MODIFY + "、修改目录节点");
		System.out.println(ACTION_DELETE + "、删除目录节点");
		System.out.println(ACTION_DEMO + "、运行Demo程序");
		System.out.println(ACTION_CONFIG + "、设置连接信息");
		System.out.println(ACTION_ABOUT + "、关于程序");
		System.out.println(ACTION_QUIT + "、退出");
		System.out.println("********************************");
	}

	public void queryData() {
		System.out.println("*****查询目录节点*****");

		String zpath = getCommand("目录节点路径", "/");

		try {
			openZk();

			printData(zpath);
			System.out.println("查询[" + zpath + "]成功!");
		} catch (Exception e) {
			System.out.println("查询[" + zpath + "]失败, 原因如下:");
			e.printStackTrace();
		}
	}

	public void createData() {
		System.out.println("*****创建目录节点*****");

		String zpath = getCommand("目录节点路径", "/");
		String zdata = getCommand("目录节点数据", zpath);
		String zacl = getCommand("目录节点权限", "0");
		String ztype = getCommand("目录节点类型", "PS");

		try {
			openZk();

			zooKeeper.create(zpath, zdata.getBytes(), getAcl(zacl), getCreateMode(ztype));
			System.out.println("创建[" + zpath + "]成功!");
		} catch (Exception e) {
			System.out.println("创建[" + zpath + "]失败, 原因如下:");
			e.printStackTrace();
		}
	}

	public void modifyData() {
		System.out.println("*****修改目录节点*****");

		String zpath = getCommand("目录节点路径", "/");
		String zdata = getCommand("目录节点数据", zpath);

		try {
			openZk();

			zooKeeper.setData(zpath, zdata.getBytes(), -1);
			System.out.println("修改[" + zpath + "]成功!");
		} catch (Exception e) {
			System.out.println("修改[" + zpath + "]失败, 原因如下:");
			e.printStackTrace();
		}
	}

	public void deleteData() {
		System.out.println("*****删除目录节点*****");

		String zpath = getCommand("目录节点路径", "/App");
		String deleteSelf = getCommand("删除节点及子节点(0/1)？", "1");
		boolean delete = "1".equals(deleteSelf);

		try {
			openZk();

			deleteNode(zpath, delete);
			System.out.println("删除[" + zpath + "]成功!");
		} catch (Exception e) {
			System.out.println("删除[" + zpath + "]失败, 原因如下:");
			e.printStackTrace();
		}
	}

	public void runDemo() {
		System.out.println("*****运行Demo程序*****");
		
		ZkMcu mcu = new ZkMcu(zkHost + ":" + zkPort, "/webmcc/operations");
		mcu.start();
		
		ZkWebmccWatcher webmccWatcher = new ZkWebmccWatcher(zkHost + ":" + zkPort, "/webmcc/kedacom");
		webmccWatcher.start();
		
		try {
			ZkWebmcc webmcc = new ZkWebmcc(zkHost + ":" + zkPort, "/webmcc/operations");
			boolean runDemo = true;
			while(runDemo) {
				int max = Integer.valueOf(getCommand("请输入要创建的节点数：", "1"));
				String data = getCommand("请输入要创建的会议主题：", "会议主题");
				for (int i = 0; i < max; i++) {
					OperationBean operation = createOperation(data + i);
					String path = webmcc.produce(JSONObject.fromObject(operation).toString());
					System.out.println("Produce Item" + i + " [" + path + "] = " + data + i);
				}
				
				String quit = getCommand("要继续运行Demo吗(Y/N)?", "N");
				if("n".equalsIgnoreCase(quit)) {
					runDemo = false;
				}
			}
			System.out.println("运行Demo程序成功!");
		} catch (KeeperException e) {
			System.out.println("运行Demo程序失败, 原因如下:");
			e.printStackTrace();
		} catch (InterruptedException e) {
			
		}
		mcu.stopRunning();
		webmccWatcher.stopRunning();
	}
	
	/** 设置连接信息 */
	public void configConnection() {
		System.out.println("*****设置连接信息*****");
		zkHost = getCommand("请输入服务器地址", zkHost);
		zkPort = Integer.valueOf(getCommand("请输入端口", "" + zkPort));
		zkTimeout = Integer.valueOf(getCommand("请输入连接超时", "" + zkTimeout));

		try {
			// 创建一个与服务器的连接
			zooKeeper = new ZooKeeper(zkHost + ":" + zkPort, zkTimeout, this);
			System.out.println("设置连接信息成功!");
		} catch (Exception e) {
			zooKeeper = null;
			System.out.println("设置连接信息失败, 原因如下:");
			e.printStackTrace();
		}
	}

	/** 关于 */
	public static void about() {
		System.out.println("************关于" + TOOL_NAME + "****************");
		System.out.println("|　　　　版本：" + TOOL_VERSION + "　　　　　　　　　　　|");
		System.out.println("|　　　　作者：" + TOOL_AUTHOR + "　　　　　　　　　　|");
		System.out.println("|　　　　　　　　　　　　　　　　　　　　|");
		System.out.println("|版本更新：　　　　　　　　　　　　　　　|");
		System.out.println("|V0.1　　　　　　　　　　　　　　　　　　|");
		System.out.println("|　　1.查询目录节点功能　　　　　　　　　|");
		System.out.println("|　　2.创建目录节点功能　　　　　　　　　|");
		System.out.println("|　　3.修改目录节点功能　　　　　　　　　|");
		System.out.println("|　　4.删除目录节点功能　　　　　　　　　|");
		System.out.println("|　　5.设置连接信息　　　　　　　　　　　|");
		System.out.println("|V0.2　　　　　　　　　　　　　　　　　　|");
		System.out.println("|　　增加运行Demo程序功能　　　　　　　　|");
		System.out.println("|　　　　　　　　　　　　　　　　　　　　|");
		System.out.println("|　　　" + TOOL_COPYRIGHT + "　　　　　　|");
		System.out.println("*****************************************");
	}

	/** 退出 */
	public static void exit() {
		System.out.println("谢谢使用，再见！");
		try {
			if (zooKeeper != null) {
				try {
					zooKeeper.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			Thread.sleep(1000);
		} catch (Exception e) {
		}
		System.exit(0);
	}

	private ZooKeeper openZk() {
		if (zooKeeper == null) {
			// 创建一个与服务器的连接
			try {
				zooKeeper = new ZooKeeper(zkHost + ":" + zkPort, zkTimeout, this);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return zooKeeper;
	}

	private List<ACL> getAcl(String zacl) {
		return Ids.OPEN_ACL_UNSAFE;
	}

	private CreateMode getCreateMode(String ztype) {
		if ("P".equalsIgnoreCase(ztype)) {
			return CreateMode.PERSISTENT;
		} else if ("PS".equalsIgnoreCase(ztype)) {
			return CreateMode.PERSISTENT_SEQUENTIAL;
		} else if ("E".equalsIgnoreCase(ztype)) {
			return CreateMode.EPHEMERAL;
		} else {
			return CreateMode.EPHEMERAL_SEQUENTIAL;
		}
	}

	private void deleteNode(String path, boolean deleteSelf) {
		try {
			if (zooKeeper.exists(path, false) == null) {
				return;
			}

			List<String> datas = zooKeeper.getChildren(path, false);
			for (String data : datas) {
				String childPath = path + "/" + data;
				List<String> children = zooKeeper.getChildren(childPath, false);
				if (children != null && !children.isEmpty()) {
					deleteNode(childPath, deleteSelf);
				}
				zooKeeper.delete(childPath, -1);
			}
			if (deleteSelf) {
				zooKeeper.delete(path, -1);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void printData(String path) {
		printData(path, "");
	}

	private void printData(String path, String prefix) {
		try {
			System.out.println(prefix + "" + path + "\n");

			if (zooKeeper.exists(path, false) == null) {
				return;
			}

			List<String> datas = zooKeeper.getChildren(path, false);
			for (int i = 0, len = datas.size(); i < len; i++) {
				String data = datas.get(i);
				if (i != len - 1) {
					System.out.print(prefix + "├─");
				} else {
					System.out.print(prefix + "└─");
				}

				if ("/".equals(path)) {
					printData(path + data, "   " + prefix);
				} else {
					printData(path + "/" + data, "   " + prefix);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private OperationBean createOperation(String data) {
		long meetingId = System.currentTimeMillis();
		OperationBean operation = new OperationBean();
		operation.setEnterprise("kedacom");
		operation.setType(OperationType.CREATE_MEETING);
		operation.setMeetingId("" + meetingId);
		operation.setData(createMeeting(meetingId, data));
		return operation;
	}
	
	private MeetingBean createMeeting(long meetingId, String subject) {
		MeetingBean meeting = new MeetingBean();
		meeting.setId((int) meetingId);
		meeting.setShortId("" + meetingId);
		meeting.setSubject("[会议] " + subject);
		meeting.setStartTime("2012-09-04 16:00:00");
		meeting.setEndTime("2012-09-04 17:00:00");
		meeting.setMeetingRoomId("12");
		meeting.setCreator("陈格生");
		meeting.setPhoneNo("8587");
		meeting.setAttendanceIds("1,5,9,134,268");
		meeting.setBrief("[" + subject + "] 会议摘要");
		return meeting;
	}

	// 获取输入信息
	public static String getCommand() {
		return getCommand("请输入命令", 1);
	}

	public static String getCommand(String message) {
		return getCommand(message, null, 100);
	}

	public static String getCommand(String message, int limit) {
		return getCommand(message, null, limit);
	}

	public static String getCommand(String message, String defaultValue) {
		return getCommand(message, defaultValue, 100);
	}

	public static String getCommand(String message, String defaultValue, int limit) {
		String strCommand = "";
		try {
			do {
				System.out.println();
				if (defaultValue == null) {
					System.out.print(message + ": ");
				} else {
					System.out.print(message + " [" + defaultValue + "]: ");
				}

				byte[] command = new byte[100];
				System.in.read(command);
				strCommand = new String(command);
				strCommand = strCommand.replaceAll("\r\n", "").trim();
				// 若存在默认值且直接输入回车，则直接使用默认值作为返回值
				if (defaultValue != null && "".equals(strCommand)) {
					strCommand = defaultValue;
				}
			} while (strCommand.length() > limit);
		} catch (Exception e) {
			System.out.println("输入错误！！！");
		}
		return strCommand;
	}
}
